#ifndef PERMUTACION_CUH
#define PERMUTACION_CUH

//Incluyo la clase Random para la generación de números aleatorios en CUDA
#include "../utils/Random.cu"

/****************** Representacion Permutacion ********************/

/******************* Declaracion de Funciones del Host *************************/
void representacionPermutacion();
void traerImprimirPermutacion(float* fitnessHost, float* fitnessDevice, int tamVectorFitnessFloat, int* poblacionHost, int* poblacionDevice, int tamVectorPoblacion);
void traerImprimirMejorIndividuoPermutacion(float* mejorFitnessIndividuoGPU, float* mejorFitnessIndividuoGPUDevice, int tamVectorFitnessMejoresIndividuosGPU, int* mejorIndividuoGPU, int* mejorIndividuoGPUDevice, int tamVectorMejoresIndividuosGPU, int iteracion);

/******************* Declaracion de Funciones Global del Device ********************/
__global__ void inicializarPoblacionPermutacion(int* poblacion, float* fitnessActualDevice, struct Random randomGPU, int cantCromosomasPoblacion, float* fitnessOrdenadoDevice, float* matrizCostosDevice);
__global__ void mainKernelPermutacion(int* poblacionActualDevice, int* nuevaPoblacionDevice, float* fitnessActualDevice, float* nuevoFitnessDevice, int* poblacionActualAcambiarDevice, int* nuevaPoblacionAcambiarDevice, int* individuosAMigrarDevice, float* probabilidadRuletaDevice, float* fitnessTotalParaRuletaDevice, struct Random r, int * individuoAMigrarGPUaCPUdevice, float* fitnessOrdenadoDevice, int* vectorIndicesFitnessOrdenado, int iteracion, int* mejorIndividuoGPUDevice, float* mejorFitnessIndividuoGPUDevice, float* matrizCostosDevice);

/******************* Declaracion de Funciones internas del Device *****************/
__device__ int obtenerMejorIndividuoPermutacion(float* vectorFitness);
__device__ void obtenerPeorIndividuoPermutacion(float* vectorFitness, int indices[2]);

__global__ void migracionRepresentacionPermutacion(int* poblacionActualDevice, float* fitnessActualDevice, int* individuosAMigrarDevice, struct Random randomGPU, int* individuoAMigrarCPUaGPUdevice, float* matrizCostosDevice);
__global__ void obtenerMejoresIndividuosPermutacion(int* poblacion, float* fitness, int* mejorIndividuoDevice, float* mejorFitnessIndividuoGPUDevice);
__device__ void individosAMigrarRepresentacionPermutacion(float* nuevoFitnessDevice, int* nuevaPoblacionDevice, int* individuosAMigrarDevice, int * individuoAMigrarGPUaCPUdevice);

__device__ void asignarProbabilidadRuletaPermutacion(float* fitnessActualDevice, float* probabilidadRuletaBinaria, float* fitnessTotalParaRuletaDevice, struct Random randomGPU);

__device__ int seleccionPermutacion(float* vectorFitness, float* probabilidadRuletaDevice, struct Random randomGPU, int ejecutarFuncion, int* vectorIndicesFitnessOrdenado);
__device__ int seleccionPorTorneoPermutacion(float* vectorFitness, struct Random randomGPU);
__device__ int seleccionPorRangoPermutacion(int* vectorIndicesFitnessOrdenado, struct Random randomGPU);
__device__ int seleccionRuedaRuletaPermutacion(float* probabilidadRuletaDevice, struct Random randomGPU);

__device__ void cruzamientoRepresentacionPermutacion(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU, int ejecutarFuncion);
__device__ void cruzamientoCromosomaPMX(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU);
__device__ void cruzamientoCromosomaOX(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU);
__device__ void cruzamientoCromosomaCX(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad,struct Random randomGPU);

__device__ void mutacionPermutacion(int* poblacion, float probabilidad, struct Random randomGPU, int ejecutarFuncion);
__device__ void mutacionPorIntercambio(int* poblacion, float probabilidad, struct Random randomGPU);
__device__ void mutacionPorInsercionSimple(int* poblacion, float probabilidad, struct Random randomGPU);
__device__ void mutacionPorInversionIVM(int* poblacion, float probabilidad, struct Random randomGPU);

__device__ void asignarFitnessPermutacion(int* poblacion, float* vectorFitness, float* fitnessOrdenadoDevice, float* matrizCostosDevice);

__device__ void reemplazoPermutacion(int* poblacionActualDevice, int* nuevaPoblacionDevice, int* poblacionActualAcambiar, int* nuevaPoblacionAcambiar, float * fitnessActualDevice, float* nuevoFitnessDevice, int ejecutarFuncion);
__device__ void reemplazoElitistaPermutacion(int* poblacionActual, int* nuevaPoblacion, int* poblacionActualAcambiar, int* nuevaPoblacionAcambiar, float * fitnessActual, float* nuevoFitness);

#endif
